<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>函数增强-默认参数详细用法</title>
  <!-- 
  在 JavaScript 中，默认参数（Default Parameters）是 ES6 引入的一项功能，允许在函数声明时为参数设置默认值。这种特性使得函数在调用时可以更加灵活，减少了对参数值的检查和赋值的需求。
  1. 基本语法
  在函数的参数列表中，可以为参数指定默认值。如果调用函数时未传入该参数，则使用默认值。
  function greet(name = '世界') {
      console.log(`你好, ${name}!`);
  }

  greet(); // 输出: 你好, 世界!
  greet('Alice'); // 输出: 你好, Alice!
  2. 多个参数的默认值
  可以为多个参数设置默认值。每个参数都可以独立指定默认值。
  function add(x = 0, y = 0) {
      return x + y;
  }

  console.log(add()); // 输出: 0
  console.log(add(5)); // 输出: 5
  console.log(add(5, 10)); // 输出: 15
  3. 默认参数与其他参数的结合
  默认参数可以与其他参数结合使用，默认参数可以放在参数列表的任意位置，但通常建议将其放在参数列表的末尾，以避免混淆。
  function multiply(a, b = 1) {
      return a * b;
  }

  console.log(multiply(5)); // 输出: 5
  console.log(multiply(5, 2)); // 输出: 10
  4. 使用表达式作为默认值
  默认参数可以是任何有效的表达式，包括函数调用、运算等。
  function getArea(width, height = width) {
      return width * height;
  }

  console.log(getArea(5)); // 输出: 25
  console.log(getArea(5, 10)); // 输出: 50
  5. 作用域与默认参数
  默认参数的值在函数调用时计算，这意味着如果默认参数是一个函数调用，则该函数会在每次调用时执行。
  function getRandomNumber() {
      return Math.random();
  }

  function logNumber(num = getRandomNumber()) {
      console.log(num);
  }

  logNumber(); // 输出: 随机数
  logNumber(5); // 输出: 5
  6. 默认参数与  `undefined` 
  如果在调用函数时显式传入  `undefined` ，则会使用默认值。这与传入  `null`  的行为不同。
  function display(value = '默认值') {
      console.log(value);
  }

  display(); // 输出: 默认值
  display(undefined); // 输出: 默认值
  display(null); // 输出: null
  7. 总结
  - 定义：默认参数允许在函数定义时为参数设置默认值。
  - 灵活性：可以在调用函数时省略参数，使用默认值。
  - 多个参数：支持为多个参数设置默认值。
  - 表达式：默认参数的值可以是任何有效的表达式。
  - 作用域：默认参数的值在函数调用时计算。
  -  `undefined`  处理：显式传入  `undefined`  会使用默认值，而传入  `null`  则不会。
  -->
</head>
<body>

  <script>
    // 1. 定义默认参数
    function greet(name = 'World') {
      console.log(`Hello, ${name}!`);
    }

    greet(); // 输出: Hello, World!
    greet('Alice'); // 输出: Hello, Alice!

    // 2. 多个参数的默认值
    function multiply(a, b = 1) {
      return a * b;
    }

    console.log(multiply(5)); // 输出: 5
    console.log(multiply(5, 10)); // 输出: 50

    // 3. 表达式作为默认参数
    function getArea(radius = 5, pi = Math.PI) {
      return pi * radius * radius;
    }

    console.log(getArea()); // 输出: 78.53981633974483
    console.log(getArea(10)); // 输出: 314.1592653589793
    console.log(getArea(10, 3.14)); // 输出: 314

    // 4. 作用域
    let defaultName = 'Default Name';
    function greetWithDefault(name = defaultName) {
      console.log(`greetWithDefault, ${name}!`);
    }

    greetWithDefault(); // 输出: Hello, Default Name!
    greetWithDefault('Alice'); // 输出: Hello, Alice!

    // 5.  `undefined`  处理
    function greetWithUndefined(name = 'greetWithUndefined') {
      // 1.两种写法不严谨
      // 默认值写法一:
      // arg1 = arg1 ? arg1: "我是默认值"

      // 默认值写法二:
      // arg1 = arg1 || "我是默认值"

      // 2.严谨的写法 - 三元运算符
      // arg1 = (arg1 === undefined || arg1 === null) ? "我是默认值": arg1
      
      // ES6之后新增语法: ??
      // arg1 = arg1 ?? "我是默认值"

      // 3.简便的写法: 默认参数
      console.log(`WithUndefined, ${name}!`);
    }

    greetWithUndefined(undefined); // 输出: WithUndefined, greetWithUndefined!
    greetWithUndefined(null); // 输出: WithUndefined, null!
    greetWithUndefined() // 输出: WithUndefined, greetWithUndefined!
    greetWithUndefined(0) // 输出: WithUndefined, 0!
    greetWithUndefined("") // 输出: WithUndefined, !
    greetWithUndefined(false) // 输出: WithUndefined, false!

    // 6.  `对象`  处理
    function greetWithObject(name = { firstName: 'Default', lastName: 'Name' }) {
      console.log(`WithObject, ${name.firstName} ${name.lastName}!`);
    }

    greetWithObject(); // 输出: WithObject, Default Name!

    // 7.  `数组`  处理
    function greetWithArray(name = ['Default', 'Name']) {
      console.log(`WithArray, ${name[0]} ${name[1]}!`);
    }

    greetWithArray(); // 输出: WithArray, Default Name!

    // 8.  `函数`  处理
    function greetWithFunction(name = () => 'Default Name') {
      console.log(`WithFunction, ${name()}!`);
    }

    greetWithFunction(); // 输出: WithFunction, Default Name!

    // 9.  `类`  处理
    const DefaultName = class {
      constructor() {
        this.firstName = 'Default';
        this.lastName = 'Name';
      }
    }
    function greetWithClass(name = DefaultName) {
      console.log(`WithClass, ${new name().firstName} ${new name().lastName}!`);
    }

    greetWithClass(); // 输出: WithClass, Default Name!

  </script>
  
</body>
</html>